━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
تمرین اول Computer Vission
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

بخش اول

مشخصات دانشجویان:

نام و نام خانوادگی: نیلوفر مرتضوی

شماره دانشجویی: 220701096


نام و نام خانوادگی: برنا فروهری

شماره دانشجویی: 810101480

زیربخش اول
تصویر Pic.jpg را بارگذاری نمایید. فرمت تصویر پس از بارگذاری، شامل نوع داده و تعداد کانال های رنگی آن را مشخص کنید.

In [8]:
# Libraries
import cv2
import numpy as np
import matplotlib.pyplot as plt
In [9]:
path = "Pic.jpg"

img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
if img is None:
    raise FileNotFoundError(f"File not found: {path}")

if img.ndim == 2:  # image 2-D and 1 channel(gray picture)
    h, w = img.shape
    channels = 1
else:  # image more than 2-D and 3 or 4 channels(BGR or BGRA)
    h, w, channels = img.shape

if channels == 1:
    color_info = "Grayscale"
elif channels == 3:
    color_info = "BGR (B=blue G=green R=red)"
elif channels == 4:
    color_info = "BGRA (B=blue G=green R=red A=alpha(transparency))"
else:
    color_info = f"{channels} Not normal channels"

print(f"Size (H×W): {h}×{w}")
print(f"Number of channels: {channels} {color_info}")
print(f"Pixel data types: {img.dtype}")
Size (H×W): 600×800
Number of channels: 3 BGR (B=blue G=green R=red)
Pixel data types: uint8

زیربخش دوم
تصویر بارگذاری شده را ابتدا با مدل رنگی RGB و سچس به تصویر در مقیاس خاکستری Graysca;e و در نهایت به تصویر Binary تبدیل نمایید. درباره هر یک از این انواع تصویر توضیح مختصری دهید.

In [10]:
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)

_, img_binary = cv2.threshold(img_gray, 128, 255, cv2.THRESH_BINARY)


plt.figure(figsize=(15,5))

plt.subplot(1, 3, 1)
plt.imshow(img_rgb)
plt.title("RGB Image")
plt.axis("off")

plt.subplot(1, 3, 2)
plt.imshow(img_gray, cmap="gray")
plt.title("Grayscale Image")
plt.axis("off")

plt.subplot(1, 3, 3)
plt.imshow(img_binary, cmap="gray")
plt.title("Binary Image")
plt.axis("off")

plt.tight_layout()
plt.show()
No description has been provided for this image

پاسخ تشریحی زیربخش دوم:
در مدل رنگی RGB هر پیکسل از سه مقدار تشکیل می‌شود که شدت رنگ‌های قرمز (Red)، سبز (Green) و آبی (Blue) را نشان می‌دهند. ترکیب این سه رنگ، رنگ نهایی پیکسل را می‌سازد. برای مثال:
(0, 0, 255) → قرمز
(0, 255, 0) → سبز
(255, 0, 0) → آبی
(255, 255, 255) → سفید
این مدل برای نمایش تصاویر در مانیتور، تلویزیون و دوربین‌ها استفاده می‌شود و مبنای اکثر پردازش‌های تصویری است.

در تصویر خاکستری، اطلاعات رنگ حذف می‌شود و تنها شدت روشنایی (Brightness) هر پیکسل حفظ می‌گردد. به‌عبارتی، تصویر فقط یک کانال دارد و هر پیکسل عددی بین 0 تا 255 دارد:
0 → سیاه
128 → خاکستری
255 → سفید
تبدیل تصویر RGB به Grayscale معمولاً با ترکیب وزنی سه رنگ اصلی انجام می‌شود تا حس روشنایی واقعی‌تری ایجاد شود. این نوع تصویر باعث کاهش حجم داده و سرعت بیشتر در پردازش می‌شود و پایه‌ی بسیاری از الگوریتم‌های بینایی ماشین مثل تشخیص لبه‌ها است.

تصویر باینری یا دو سطحی حالتی از تصویر است که در آن هر پیکسل فقط دو مقدار ممکن دارد:
0 → سیاه
1 یا 255 → سفید
برای ساختن تصویر باینری، معمولاً ابتدا تصویر خاکستری گرفته می‌شود و سپس با اعمال یک آستانه (Threshold)، پیکسل‌های روشن‌تر از مقدار آستانه سفید و بقیه سیاه می‌شوند. به‌طور مثال، اگر آستانه 128 باشد:
پیکسل‌هایی با مقدار > 128 → سفید
پیکسل‌هایی با مقدار ≤ 128 → سیاه
این تصاویر در شمارش اشیا، تشخیص مرزها، ماسک‌گذاری، OCR (تشخیص متن) و سایر کاربردهای پردازش تصویر استفاده می‌شوند.

زیربخش سوم
توضیح مختصری در مورد مدل رنگی HSV ارائه دهید و تصویر بارگذاری شده را به این مدل نیز تبدیل کنید.

In [11]:
img_hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)

plt.figure(figsize=(12,5))

plt.subplot(1, 2, 1)
plt.imshow(img_rgb)
plt.title("RGB Image")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.imshow(img_hsv)
plt.title("HSV Image")
plt.axis("off")

plt.tight_layout()
plt.show()
No description has been provided for this image

پاسخ تشریحی زیربخش سوم:
در مدل‌های رنگیِ مورد استفاده در بینایی ماشین، HSV (مخفف Hue–Saturation–Value) یکی از رایج‌ترین و کارآمدترین‌هاست؛ زیرا رنگ را شبیه‌تر به شیوه‌ی ادراک انسان مدل می‌کند. مؤلفه‌ی H (Hueیا فام) نوع رنگ را نشان می‌دهد (مثلاً قرمز، زرد، سبز، آبی) و به‌صورت زاویه روی دایره‌ ی رنگ تعریف می‌شود؛ در تئوری 0 تا 360 درجه است، اما در پیاده‌سازی OpenCV به‌دلیل استفاده از داده‌ی ۸بیتی، در بازه‌ی 0 تا 179 کدگذاری می‌شود (یعنی مقادیر نصف شده‌اند). مؤلفه‌ی S (Saturationیا اشباع) خلوص رنگ را مشخص می‌کند: هرچه S بزرگ‌تر باشد، رنگ خالص‌تر است؛ S=0 تصویری بی‌رنگ و خاکستری می‌دهد. مؤلفه‌ی V (Valueیا روشنایی) شدت روشنایی را کنترل می‌کند: V=0 سیاه مطلق و V=255 بیش‌ترین درخشندگی است. جداسازی نوع رنگ (H) از شدت (V) باعث می‌شود بسیاری از عملیات رنگ‌ محور مثل تفکیک یک رنگ خاص در پس‌زمینه‌های پیچیده یا شرایط نوری متغیر—پایدارتر از فضای RGB انجام شوند. به‌عنوان مثال، وقتی نور محیط کم‌وزیاد می‌شود، تغییر عمده روی V رخ می‌دهد و شما می‌توانید با نگه‌داشتن محدوده‌ی H و S و فقط به‌روز کردن آستانه‌های V، همان رنگ را تشخیص دهید. تبدیل تصویر RGB به HSV معمولاً اولین گام در کارهای عملی مثل استخراج ناحیه با یک رنگ مشخص (Color Segmentation)، ردیابی اشیاء بر اساس رنگ در ویدئو، تشخیص پوست یا فیلتر کردن نویز رنگی است. نقطه‌ی قوت HSV این است که «فام» را مستقل‌تر از روشنایی نگه می‌دارد.

زیربخش چهارم
هر یک از تصاویر RGB و HSV را به مولفه های تشکیل دهنده ی آن ها تفکیک کرده و هر مولفه را به صورت جداگانه نمایش دهید.

In [14]:
R, G, B = cv2.split(img_rgb)

R_colored = np.dstack([R, np.zeros_like(R), np.zeros_like(R)])
G_colored = np.dstack([np.zeros_like(G), G, np.zeros_like(G)])
B_colored = np.dstack([np.zeros_like(B), np.zeros_like(B), B])

plt.figure(figsize=(14,8))

plt.subplot(2, 3, 1)
plt.imshow(R, cmap="gray")
plt.title("R gray")
plt.axis("off")

plt.subplot(2, 3, 4)
plt.imshow(R_colored)
plt.title("Red")
plt.axis("off")

plt.subplot(2, 3, 2)
plt.imshow(G, cmap="gray")
plt.title("G gray")
plt.axis("off")

plt.subplot(2, 3, 5)
plt.imshow(G_colored)
plt.title("Green")
plt.axis("off")

plt.subplot(2, 3, 3)
plt.imshow(B, cmap="gray")
plt.title("B gray")
plt.axis("off")

plt.subplot(2, 3, 6)
plt.imshow(B_colored)
plt.title("Blue")
plt.axis("off")

plt.tight_layout()
plt.show()

H, S, V = cv2.split(img_hsv)

plt.figure(figsize=(14,5))

plt.subplot(1, 4, 1)
plt.imshow(cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB))
plt.title("HSV Image")
plt.axis("off")

plt.subplot(1, 4, 2)
plt.imshow(H, cmap="gray", vmin=0, vmax=179)
plt.title("H (Hue: 0..179)")
plt.axis("off")

plt.subplot(1, 4, 3)
plt.imshow(S, cmap="gray", vmin=0, vmax=255)
plt.title("S (Saturation: 0..255)")
plt.axis("off")

plt.subplot(1, 4, 4)
plt.imshow(V, cmap="gray", vmin=0, vmax=255)
plt.title("V (Value: 0..255)")
plt.axis("off")

plt.tight_layout()
plt.show()
No description has been provided for this image
No description has been provided for this image

پاسخ تشریحی زیربخش چهارم:
تفکیک RGB: تصویر رنگی (RGB) از سه کانال R، G، B تشکیل شده است که به‌ترتیب شدت قرمز، سبز و آبی را در هر پیکسل ذخیره می‌کنند. با جدا کردن هر کانال، یک تصویر تک‌کاناله (خاکستری) به‌دست می‌آید که روشنایی آن، شدت همان مولفه را نشان می‌دهد. برای نمایش «تأکید رنگی»، همان کانال را در جای خودش نگه می‌داریم و دو کانال دیگر را صفر می‌کنیم (مثلاً R_colored فقط قرمز را نشان می‌دهد).

تفکیک HSV: در فضای HSV سه مولفه داریم:
H (Hue/فام): نوع رنگ (قرمز، آبی، …). در OpenCV بین 0 تا 179 کدگذاری می‌شود.
S (Saturation/اشباع): خلوص رنگ؛ نزدیک 0 یعنی بی‌رنگ/خاکستری.
V (Value/روشنایی): شدت روشنایی؛ صفر سیاه مطلق. نمایش هر مولفه به‌صورت تک‌کاناله، ساختار رنگی تصویر را از منظر فام/اشباع/روشنایی نشان می‌دهد.

زیربخش پنجم
کنتراست (Contrast) را تعریف کرده و مقدار آن را برای تصویر محاسبه کنید. سپس یک بار کنتراست را افزایش و یک بار کاهش دهید و نتایج را نمایش دهید.

In [17]:
gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY).astype(np.float32) / 255.0  # normalize to [0,1]

def rms_contrast(I01: np.ndarray):
    return float(I01.std())

C0 = rms_contrast(gray)

def adjust_contrast_linear_rgb(img_rgb_uint8: np.ndarray, alpha:float, pivot:float = 0.5):
    img01 = img_rgb_uint8.astype(np.float32) / 255.0
    out01 = alpha * (img01 - pivot) + pivot
    out01 = np.clip(out01, 0.0, 1.0)
    return (out01 * 255.0).round().astype(np.uint8)

alpha_increase = 1.8
alpha_decrease = 0.4

img_more_contrast = adjust_contrast_linear_rgb(img_rgb, alpha=alpha_increase, pivot=0.5)
img_less_contrast = adjust_contrast_linear_rgb(img_rgb, alpha=alpha_decrease, pivot=0.5)

gray_more = cv2.cvtColor(img_more_contrast, cv2.COLOR_RGB2GRAY).astype(np.float32) / 255.0
gray_less = cv2.cvtColor(img_less_contrast, cv2.COLOR_RGB2GRAY).astype(np.float32) / 255.0

C_more = rms_contrast(gray_more)
C_less = rms_contrast(gray_less)

print(f"Orginal Contrast(RMS): {C0:.4f}")
print(f"Increased Contrast(α={alpha_increase}): {C_more:.4f}")
print(f"Decreased Contrast(α={alpha_decrease}): {C_less:.4f}")

plt.figure(figsize=(16,8))

plt.subplot(2,3,1)
plt.imshow(img_rgb)
plt.title(f"Orginal(RMS={C0:.4f})")
plt.axis("off")

plt.subplot(2,3,2)
plt.imshow(img_more_contrast)
plt.title(f"Increased Contrast (α={alpha_increase}, RMS={C_more:.4f})")
plt.axis("off")

plt.subplot(2,3,3)
plt.imshow(img_less_contrast)
plt.title(f"Decreased Contrast (α={alpha_decrease}, RMS={C_less:.4f})")
plt.axis("off")

plt.subplot(2,3,4)
plt.imshow(gray, cmap="gray", vmin=0, vmax=1)
plt.title("Orginal Gray")
plt.axis("off")

plt.subplot(2,3,5)
plt.imshow(gray, cmap="gray", vmin=0, vmax=1)
plt.title("Increased Gray")
plt.axis("off")

plt.subplot(2,3,6)
plt.imshow(gray_less, cmap="gray", vmin=0, vmax=1)
plt.title("Decreased Gray")
plt.axis("off")

plt.tight_layout()
plt.show()
Orginal Contrast(RMS): 0.2296
Increased Contrast(α=1.8): 0.3088
Decreased Contrast(α=0.4): 0.0919
No description has been provided for this image

پاسخ تشریحی زیربخش پنجم:
کنتراست به معنای اختلاف در میزان روشنایی یا تیرگی بین نقاط مختلف یک تصویر است. هرچه اختلاف بین نواحی روشن و تیره بیشتر باشد، تصویر کنتراست بالاتری دارد و جزئیات آن واضح‌تر دیده می‌شوند. در مقابل، اگر شدت روشنایی در همه نقاط تقریباً مشابه باشد، تصویر کنتراست پایینی دارد و کم‌عمق یا مه‌آلود به‌نظر می‌رسد. در واقع، کنتراست شاخصی از میزان تغییر شدت پیکسل‌ها در تصویر است. در بینایی ماشین و پردازش تصویر، اندازه‌گیری عددی آن معمولاً با روش RMS (Root Mean Square Contrast) انجام می‌شود. در این روش، ابتدا تصویر به حالت خاکستری (Grayscale) تبدیل می‌شود و سپس انحراف معیار شدت روشنایی پیکسل‌ها محاسبه می‌گردد. هرچه انحراف معیار بیشتر باشد، پراکندگی روشنایی بیشتر و در نتیجه کنتراست بالاتر است. همواره مثبت و بدون واحد است؛ هرچه بزرگ‌تر باشد، کنتراست تصویر بیشتر است.

برای تغییر کنتراست از یک رابطه‌ی خطی ساده استفاده می‌کنیم که مقدار هر پیکسل را حول نقطه‌ی میانی روشنایی (مثلاً ۰.۵ در بازه‌ی نرمال‌شده) افزایش یا کاهش می‌دهد
Inew=α×(I−0.5)+0.5
در این رابطه، اگر α > 1 باشد، اختلاف بین مقادیر زیاد می‌شود و تصویر کنتراست بیشتری پیدا می‌کند (نواحی روشن روشن‌تر و نواحی تاریک تیره‌تر می‌شوند). اگر α < 1 باشد، اختلاف روشنایی کاهش می‌یابد و تصویر کنتراست کمتری خواهد داشت (رنگ‌ها تخت و بی‌روح به نظر می‌رسند). برای مثال در آزمایش، اگر مقدار α=1.4 انتخاب شود، تصویر واضح‌تر و عمیق‌تر دیده می‌شود و مقدار RMS کنتراست نیز بزرگ‌تر می‌شود. برعکس، اگر α=0.7 باشد، کنتراست کمتر و تصویر مه‌آلودتر دیده می‌شود. پس از انجام این تغییرات، می‌توان کنتراست هر تصویر را دوباره محاسبه و مقایسه کرد تا اثر فرمول مشاهده شود.

زیربخش ششم
هیستوگرام یک تصویر را تعریف کرده و نمودار هیستوگرام تصویر بارگذاری شده را ترسیم نمایید.

In [ ]:
gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)

def hist_uint8(arr):
    counts, bin_edges = np.histogram(arr.ravel(), bins=256, range=(0, 255))
    return counts, bin_edges

hist_gray, bins_gray = hist_uint8(gray)
R, G, B = cv2.split(img_rgb)
hist_R, _ = hist_uint8(R)
hist_G, _ = hist_uint8(G)
hist_B, _ = hist_uint8(B)

plt.figure(figsize=(14,5))

plt.subplot(1,2,1)
plt.imshow(img_rgb)
plt.title("Input Image(RGB)")
plt.axis("off")

plt.subplot(1,2,2)
plt.plot(bins_gray[:-1], hist_gray)
plt.title("Gray Image Histogram")
plt.xlabel("Brightness(0..255)")
plt.ylabel("Number of Pixels")
plt.grid(True, linewidth=0.3)

plt.tight_layout()
plt.show()

plt.figure(figsize=(7,5))
plt.plot(hist_B, label="B")
plt.plot(hist_R, label="R")
plt.plot(hist_G, label="G")
plt.title("RGB Histograms")
plt.xlabel("Brightness(0..255)")
plt.ylabel("Number of Pixels")
plt.legend()
plt.grid(True, linewidth=0.3)
plt.tight_layout()
plt.show()
No description has been provided for this image
No description has been provided for this image

پاسخ تشریحی زیربخش ششم:
هیستوگرام تصویر توزیع فراوانیِ مقادیر شدت روشنایی پیکسل‌ها را نشان می‌دهد. برای تصویر خاکستری، محور افقی سطوح شدت (معمولاً ۰ تا ۲۵۵) و محور عمودی تعداد پیکسل‌هایی است که آن شدت را دارند. برای تصویر رنگی، می‌توان هیستوگرام را برای هر کانال (R,G,B) به‌صورت جدا رسم کرد. هیستوگرام کمک می‌کند بفهمیم تصویر تاریک/روشن است، کنتراست پایین/بالا دارد، یا بخش بزرگی از پیکسل‌ها حول چه شدت‌هایی متمرکز شده‌اند. از هیستوگرام در کارهایی مثل برابر‌سازی کنتراست (Histogram Equalization)، آستانه‌گذاری و تحلیل کیفیت استفاده می‌شود.
گر قله‌های هیستوگرام در سمت چپ فشرده باشند، تصویر غالباً تاریک است؛ اگر در سمت راست فشرده باشند، تصویر روشن است. هیستوگرام پهن و پخش‌شده نشانه‌ی کنتراست بالا و هیستوگرام باریک نشانه‌ی کنتراست پایین است. هیستوگرام کانال‌های R/G/B نشان می‌دهد کدام رنگ‌ها غالب هستند (مثلاً در تصویر طبیعت، معمولاً G بیشتر است).

زیر بخش هفتم
درباره ی مفاهیم Histogram Equalization و Histogram Stretching تحقیق کنید و هر یک از این روش ها را بر روی تصویر اعمال کنید.

In [ ]:
gray_eq = cv2.equalizeHist(gray)

img_ycrcb = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2YCrCb)
Y, Cr, Cb = cv2.split(img_ycrcb)
Y_eq = cv2.equalizeHist(Y)
img_ycrcb_eq = cv2.merge([Y_eq, Cr, Cb])
rgb_eqY = cv2.cvtColor(img_ycrcb_eq, cv2.COLOR_YCrCb2RGB)


def stretch_minmax(img_u8):
    i_min = img_u8.min()
    i_max = img_u8.max()
    if i_max == i_min:
        return img_u8.copy()
    out = (img_u8.astype(np.float32) - i_min) / (i_max - i_min) * 255.0
    return np.clip(out, 0, 255).astype(np.uint8)

def stretch_percentile(img_u8, p_low=2, p_high=98):
    lo = np.percentile(img_u8, p_low)
    hi = np.percentile(img_u8, p_high)
    if hi <= lo:
        return img_u8.copy()
    out = (img_u8.astype(np.float32) - lo) / (hi - lo) * 255.0
    return np.clip(out, 0, 255).astype(np.uint8)

gray_stretch = stretch_minmax(gray)
gray_stretch_robust = stretch_percentile(gray, 2, 98)

Y_stretch = stretch_percentile(Y, 2, 98)
img_ycrcb_st = cv2.merge([Y_stretch, Cr, Cb])
rgb_stretch = cv2.cvtColor(img_ycrcb_st, cv2.COLOR_YCrCb2RGB)

hist_gray, bins_gray = hist_uint8(gray)
hist_gray_eq, _ = hist_uint8(gray_eq)
hist_gray_st, _ = hist_uint8(gray_stretch)
hist_gray_st_r, _ = hist_uint8(gray_stretch_robust)

plt.figure(figsize=(16,10))

plt.subplot(2,4,1); plt.imshow(img_rgb)
plt.title("Original RGB")
plt.axis("off")

plt.subplot(2,4,2); plt.imshow(gray, cmap="gray")
plt.title("Original Grayscale")
plt.axis("off")

plt.subplot(2,4,3); plt.imshow(gray_eq, cmap="gray")
plt.title("Equalized (Gray)")
plt.axis("off")

plt.subplot(2,4,4); plt.imshow(rgb_eqY)
plt.title("Equalized on Y channel (Color)")
plt.axis("off")

plt.subplot(2,4,5); plt.imshow(gray_stretch, cmap="gray")
plt.title("Stretch (Gray, Min-Max)")
plt.axis("off")

plt.subplot(2,4,6); plt.imshow(gray_stretch_robust, cmap="gray")
plt.title("Stretch (Gray, 2%-98%)")
plt.axis("off")

plt.subplot(2,4,7); plt.imshow(rgb_stretch)
plt.title("Stretch on Y channel (Color)")
plt.axis("off")

plt.tight_layout()
plt.show()

plt.figure(figsize=(10,6))

plt.plot(bins_gray[:-1], hist_gray_eq, label="Equalized", linewidth=2)
plt.plot(bins_gray[:-1], hist_gray_st, label="Stretch Min-Max", linewidth=2)
plt.plot(bins_gray[:-1], hist_gray_st_r, label="Stretch 2%-98%", linewidth=2)

plt.title("Grayscale Histogram Comparison: Before vs After", fontsize=13)
plt.xlabel("Intensity (0–255)", fontsize=12)
plt.ylabel("Pixel Count", fontsize=12)
plt.legend()
plt.grid(True, linewidth=0.4)
plt.tight_layout()
plt.show()
No description has been provided for this image
No description has been provided for this image

پاسخ تشریحی زیربخش هفتم:
یکی از مهم‌ترین روش‌های بهبود کیفیت بصری تصویر، افزایش کنتراست است. در بسیاری از تصاویر، به‌خصوص آن‌هایی که در شرایط نوری نامناسب یا با کیفیت پایین گرفته می‌شوند، شدت روشنایی پیکسل‌ها در بازه‌ای محدود متمرکز است و در نتیجه تصویر «تخت» و کم‌عمق به نظر می‌رسد. برای رفع این مشکل از دو روش رایج استفاده می‌شود: برابر‌سازی هیستوگرام (Histogram Equalization) و کشیدن هیستوگرام (Histogram Stretching). هر دو روش با هدف بازتوزیع شدت روشنایی پیکسل‌ها برای افزایش وضوح و جزئیات تصویر به کار می‌روند، اما از نظر منطق و نتیجه تفاوت‌هایی دارند.

در روش Histogram Equalization، ایده اصلی آن است که اگر بخش بزرگی از پیکسل‌ها در ناحیه‌ای خاص از هیستوگرام (مثلاً شدت‌های تیره یا روشن) متمرکز باشند، باید این مقادیر به‌گونه‌ای بازپخش شوند که توزیع شدت‌ها در کل بازه 0 تا 255 یکنواخت‌تر گردد. برای این کار ابتدا تابع توزیع تجمعی (CDF) از هیستوگرام تصویر محاسبه می‌شود و سپس هر سطح شدت ورودی با مقدار نرمال‌شدهٔ متناظر در این CDF جایگزین می‌گردد. حاصل این نگاشت آن است که نواحی تیره، روشن‌تر و نواحی خیلی روشن، متعادل‌تر دیده می‌شوند و در مجموع، تصویر دارای تضاد (کنتراست) بهتری می‌شود. این روش معمولاً روی تصاویر خاکستری اجرا می‌شود، زیرا برابر‌سازی مستقیم هر سه کانال رنگی RGB می‌تواند باعث تغییرات ناخواسته در رنگ شود. در تصاویر رنگی حرفه‌ای، این فرایند معمولاً فقط روی کانال روشنایی انجام می‌شود (مثلاً در فضای رنگی YCrCb یا HSV فقط روی Y یا V). نسخهٔ پیشرفته‌تر آن که برای جلوگیری از تقویت نویز و حفظ جزئیات در نواحی مختلف استفاده می‌شود، روش CLAHE (Contrast Limited Adaptive Histogram Equalization) نام دارد که برابر‌سازی را در کاشی‌های کوچک از تصویر انجام می‌دهد و سپس نتایج را ترکیب می‌کند. در نتیجهٔ اجرای این روش، هیستوگرام خروجی تصویر پخش‌شده‌تر و یکنواخت‌تر می‌شود و جزئیات پنهان در بخش‌های تاریک یا خیلی روشن، قابل رؤیت‌تر خواهند بود. البته باید توجه داشت که اگر نویز زیادی در تصویر وجود داشته باشد، این روش ممکن است آن را نیز تقویت کند.

در مقابل، روش کِشیدن هیستوگرام یا Contrast Stretching رویکردی ساده‌تر و خطی دارد. در این روش، کمینه و بیشینهٔ شدت روشنایی در تصویر شناسایی می‌شوند و سپس مقادیر شدت پیکسل‌ها به‌گونه‌ای خطی نگاشت می‌شوند که کمترین مقدار به 0 و بیشترین مقدار به 255 برسد و سایر مقادیر نیز متناسب بین این دو گسترش یابند. این کار باعث می‌شود محدودهٔ شدت‌های استفاده‌شده در تصویر گسترش پیدا کند و در نتیجه کنتراست افزایش یابد. به‌ترتیب کمترین و بیشترین شدت پیکسل‌ها در تصویر اصلی هستند. این تبدیل مقدارهای روشنایی را به گونه‌ای «کِش» می‌دهد که همهٔ شدت‌ها از بازهٔ 0 تا 255 استفاده کنند. در عمل، گاهی وجود چند پیکسل پرت (outlier) ممکن است باعث شود که مقدار نامناسبی بگیرد و نتیجهٔ تصویر غیرطبیعی شود. برای جلوگیری از این اتفاق از نسخهٔ مقاوم (Robust Stretching) استفاده می‌شود که به جای کمینه و بیشینهٔ مطلق، از صدک‌های 2٪ و 98٪ استفاده می‌کند. به این ترتیب، مقادیر بسیار کم یا زیاد نادیده گرفته می‌شوند و خروجی متعادل‌تر خواهد بود مزیت بزرگ این روش سادگی و سرعت بالای آن است. برخلاف برابر‌سازی هیستوگرام که توزیع را تغییر می‌دهد، در این روش شکل کلی هیستوگرام حفظ می‌شود و تنها دامنهٔ آن گسترش می‌یابد. به همین دلیل، تصویر خروجی طبیعی‌تر و رنگ‌ها وفادارتر به واقعیت خواهند بود.

در برابر‌سازی هیستوگرام، شدت‌ها به‌گونه‌ای تغییر می‌کنند که کل بازهٔ دینامیکی تقریباً به‌صورت یکنواخت پوشش داده شود؛ بنابراین جزئیات بیشتری در نواحی تیره یا روشن آشکار می‌گردد. اما گاهی رنگ‌ها تغییر کرده و تصویر بیش‌ازحد مصنوعی به نظر می‌رسد. در مقابل، در کشیدن هیستوگرام، افزایش کنتراست به شکل خطی انجام می‌شود و رنگ و شکل کلی تصویر حفظ می‌گردد، ولی میزان بهبود کنتراست معمولاً کمتر از برابر‌سازی است. Histogram Equalization برای تصاویری مناسب است که کنتراست بسیار پایین دارند و می‌خواهیم جزئیات پنهان را آشکار کنیم. Histogram Stretching برای تصاویری مفید است که دامنهٔ شدتشان محدود است ولی توزیع کلی قابل‌قبول دارد، و ما فقط می‌خواهیم تصویر شفاف‌تر و پرکنتراست‌تر شود.